// ----any
let id: any = "aaa";
// id:有可能是数字 有可能是string
console.log(id.length);
id = {
  name: "marvin",
  age: 18,
};
const info: any[] = ["1", 1, {}];

// ---unkown
// 和any 相似 但一切操作不合法
let foo: any = "000";
foo = 123;

let foo1: unknown = "000";
// foo1.length;  //报错

//类型缩小
if (typeof foo1 === "string") {
  foo1.length;
  foo1.split("");
}

function sum(): void {
  return undefined; //允许
}

const fn: () => number = (): number => 3;
type FunType1 = (...arg: any[]) => number;
const fn2: FunType1 = () => {
  return 1;
};

type FunType2 = (x: number, y: string) => number;
const fn3: FunType2 = () => {
  return 1;
};

function fff(fn: FunType2) {
  fn(1, "a");
}
fff((age, name) => {
  return age;
});
fff(() => {
  return 0;
});

const strArray = ["a", "b", "c"];
// 匿名函数有自动推导  可以根据上下文自动推导出item 和 返回值类型 不强制要求返回值为void
strArray.forEach((item) => {
  return []; //定义的是 void  但这里可以 return 任何
});

// --never --很少主动定义
function foo2(): never {
  while (true) {
    console.log(1223);
  }
  // throw new Error("12");
}

function parseLyric2() {
  return []; //never[]  返回一个数组 里面从来不会有数据
}

function handleMessage(message: string | number | boolean) {
  switch (typeof message) {
    case "string":
      console.log(message.length);
      break;
    case "number":
      console.log(message);
      break;
    case "boolean":
      console.log(message);
      break;
    default:
      const check: never = message; //
  }
}
handleMessage(true);

//tuple ---元组
const person: any[] = ["marvin", 18, 1.88];
const age11 = person[1]; //age11 --any

const person2 = {
  name: "marvin",
  age: 18,
  height: 1.88,
};

const person3: [string, number, number] = ["marvin", 18, 1.88];
const height = person3[2]; //number

// 函数中使用元组很多 特别是返回值
function useState<T>(initState: T): [T, (newValue: T) => void] {
  let stateValue = initState;
  function setValue(newValue: T) {
    stateValue = newValue;
  }
  return [stateValue, setValue];
}
const [count, setCount] = useState("100");
setCount("5");

// 联合类型
type dddd = string | number;

//交叉类型

// type
type myNumber = number;
type IDType = string | number;
function printID(id: IDType) {
  console.log(id);
}
type poType = { x: number; y: number };
function printCoordinate(p: poType) {}

// interface  接口
interface pointType2 {
  x: number;
  y: number;
}

// type 和interface 区别
// 1.type 可以声明联合类型 使用范围更广 接口只能声明对象
// 2 interface 可以多次声明 可以继承 可以被类实现

// type tt = {
//   x: number;
//   y: number;
// };

// type tt = {
//   z?: number;
// };

interface pointType {
  x: number;
  y: number;
}

interface pointType {
  z: number;
}

const point: pointType = {
  x: 0,
  y: 0,
  z: 0,
};

interface IPerson {
  name: string;
  age: number;
}

interface IKun extends IPerson {
  sing: () => void;
}

const ikun: IKun = {
  name: "ikun",
  age: 18,
  sing() {},
};

class Person implements IPerson {
  name: string = "marvin";
  age: number = 18;
}

// 推荐： //非对象类型用type 对象类型用interface

// 交叉类型 取所有的属性 合并类型
type aaa = string & number; //never

interface ICode {
  name: string;
  age: number;
}

const iikun: ICode & IKun = {
  name: "ikun",
  age: 18,
  sing() {},
};

//as
// const div = document.querySelector("div"); //HTMLDivElement | null
// const img = document.querySelector("img"); //HTMLImageElement | null
// const img2 = document.querySelector(".img"); //--Element
// const img3 = img2 as HTMLImageElement;
// img3.src = ""; //Element ==> HTMLImageElement  多态 强制类型转换

interface IPerson2 {
  friend?: {
    name: string;
  };
}

// 非空类型断言
const pp: IPerson2 = {
  friend: {
    name: "123",
  },
};
console.log(pp.friend?.name);
//强制告诉 ts friend 不为空
pp.friend!.name = "123";

//字面量类型

let age: 18 = 18;
const age2 = 18;

type Direction = "left" | "right";
let dr: Direction = "right";
type Methods = "get" | "post";
function request(url: string, method: "get" | "post") {}

type Indo = {
  url: string;
  method: Methods;
};
const indo: Indo = {
  url: "http:;;",
  method: "post",
};
request(indo.url, indo.method as "get" | "post");

// 函数类型
function fooo() {}

const fooo1 = () => {};

let a = new Person();
console.log(a);

// function calc(fn: any) {
//   const num1 = 10;
//   const num2 = 20;
//   return fn(num1, num2);
// }

// const result = calc((x: any, y: any) => {
//   return x + y;
// });
// console.log(result);

function calc(fn: (x: number, y: number) => number) {
  return fn(10, 20);
}
const result = calc((x, y) => {
  return x + y;
});
console.log(result);

const result2 = calc((x) => {
  return x;
});
console.log(result2);

interface IPerson4 {
  name: string;
}

const p2 = {
  name: "marvin",
  age: 18,
};
const p: IPerson4 = p2; //typescript 认为 p2 定义过 不是第一次了 所以不再检测参数个数
const p0: IPerson4 = {
  name: "marvin",
  // age: 18,  //报错  //第一次定义的时候  会检测参数个数 所以这里报错
};

//函数类型-->调用签名
const Bar2 = (x: number): void => {};
// Bar2.name = "123"; //报错
const Bar: () => void = () => {};
// Bar.name = "123"; //报错  //Bar 本来是一个构造函数  可以定义全局 静态属性 但这样指定后就不行了
interface IBar {
  uname: string; //不要取 name 怕和内部命名冲突
  age: number;
  (): void; //调用签名  //有了这个声明 函数才能被调用
}
const Bar3: IBar = () => {};
Bar3.uname = "123";
Bar3.age = 18;
Bar3();

// 函数类型 构造签名  new():T

// 箭头函数不能用new 来构造 箭头函数没有原型
// const bar = new Bar3(); //bar --> any  报错箭头函数不能作为构造函数 因为箭头函数没有原型 也就没有构造器
// console.log(bar);

interface ICTORPerson<T> {
  new (): T; //构造签名  有了这个 才能当成构造函数
}

function factory(fn: ICTORPerson<Son>) {
  const f = new fn();
  return f;
}

class Son {
  uname = "son";
  age = 8;
  sing() {
    console.log(" i am singing");
  }
}
// Son 也是一个构造函数
const son = factory(Son);
son.sing();

function foo4(x: number, y?: number) {
  if (y !== undefined) {
    console.log(123);
  }
}

function foo5(x: number, y = 10) {}
foo5(10, undefined); //m默认参数 可以接受 undefined 不会报错 会忽律

// 剩余参数
function foo6(...arg: (string | number)[]) {}

//函数重载
function add(x: number, y: number): number;
function add(x: string, y: string): string;
function add(x: any, y: any) {
  return x + y;
}
let res = add(10, 20);
let res2 = add("10", "10");
// res = add("10", 10);

//重载和联合类型
// function getLength(arg: string): number;
// function getLength(arg: number[]): number;
// function getLength(arg: any) {
//   return arg.length;
// }

//官方推荐使用
// function getLength(arg: any[] | string): number {
//   return arg.length;
// }

function getLength(arg: { length: number }): number {
  return arg.length;
}

getLength("aaa");

// ---this
const obhe = {
  name: "marivn",
  sing() {
    console.log(this.name);
  },
};
obhe.sing();

// function foo7() {
//   console.log(this);  报错 // tsconfig 配置 "noImplicitThis": true 这里会推导this   any 的this 编译不过
// }

//可以进行指定
function foo8(this: {}, arg: any) {
  console.log(this, arg); // tsconfig 配置 "noImplicitThis": true 这里会推导this   any 的this 编译不过
}
foo8.call({ name: "marvin" }, 123);
// foo8(123);//报错
// window.foo8(123); //这也制定了 this 为window

function foo9(this: { name: string }, info: { name: number }) {
  console.log(this, info);
}

foo9.call({ name: "marvin" }, { name: 5 });

//获取函数 this 的类型
type Foo9Type = typeof foo9; //先获取函数类型
type foo9ThisType = ThisParameterType<Foo9Type>;

//剔除 this 的函数类型
type PureFootype = OmitThisParameter<Foo9Type>;

//实现自己的store
type IState = {
  name: string;
};
interface IStore {
  state: IState;
  changeName: () => void;
  changeName2: () => void;
  changeName3: () => void;
}

// const store: IStore  = {
//   state: {
//     name: "aaa",
//   },
//   changeName: function () {
//     this.state.name = "bbb";
//     console.log(this.state.name);
//   },
//   changeName2: function (this: IState) {
//     this.name = "ccc";
//     console.log(this.name);
//   },
//   changeName3: function (this: IState) {
//     this.name = "ddd";
//     console.log(this.name);
//   },
// };
// store.changeName();
// store.changeName2.call(store.state);

//给 Store 对象绑定this 为IState
const store: IStore & ThisType<IState> = {
  state: {
    name: "aaa",
  },
  changeName: function () {
    this.name = "bbb";
    console.log(this.name);
  },
  changeName2: function () {
    this.name = "ccc";
    console.log(this.name);
  },
  changeName3: function () {
    this.name = "ddd";
    console.log(this.name);
  },
};
store.changeName();
store.changeName2();

export {};
